package com.mly.data.algo;
//插入排序算法、冒泡排序算法、选择排序算法、归并排序算法、快速排序算法、堆排序算法
public class Sorts {

    private  int[] sortArr;
    private  int  n;

    public Sorts(int[] sortArr, int n) {
        this.sortArr = sortArr;
        this.n = n;
    }

    public int[] insertionSort(){
        for(int i=1;i<n;i++){
            int value = sortArr[i];
            int j = i-1;
            for(;j>=0;j--){
                if(sortArr[j]>value){
                    sortArr[j+1] = sortArr[j];
                }else{
                    break;
                }
            }
            sortArr[j+1] = value;
        }
        return sortArr;
    }

    public int[] bubbleSort(){
        for(int i=0;i<n;i++){
            boolean flag = false;
            for(int j=0;j<n-i-1;j++){
                if(sortArr[j]>sortArr[j+1]){
                    int tmp = sortArr[j];
                    sortArr[j] = sortArr[j+1];
                    sortArr[j+1] = tmp;
                    flag = true;
                }
            }
            if(!flag){
                break;
            }
        }
        return sortArr;
    }

    public int[] selectionSort(){
        for(int i=0;i<n-1;i++){
            int minIndex = i;
            for(int j=i+1;j<n;j++){
                if(sortArr[j]<sortArr[minIndex]){
                    minIndex = j;
                }
            }
            int tmp = sortArr[i];
            sortArr[i] = sortArr[minIndex];
            sortArr[minIndex] = tmp;
        }
        return sortArr;
    }

    /**
     * 递归排序写法
     * 1：写出递推公式
     * 2：找出终止条件
     * f(n) = f(n-1)+1
     * f(1) = 1;
     * 递推公式：mergeSort_c(p,r) = merge(mergeSort_c(p,q),mergeSort_c(q+1,r))
     * 终止条件：p>=r
     * @return
     */
    public int[] mergeSort(){
        mergeSort_c(sortArr,0,n-1);
        return sortArr;
    }

    private void mergeSort_c(int[] sortArr, int p, int r) {
        if(p>=r) return;
        int q = (p+r)/2;
        mergeSort_c(sortArr,p,q);
        mergeSort_c(sortArr,q+1,r);
        merge(sortArr,p,q,r);
    }
    //归并排序merge方法时间复杂度为O(n)
    private void merge(int[] sortArr, int p, int q, int r) {
        int i = p;
        int j = q+1;
        int k = 0;
        int []tmp = new int[r-p+1];
        while(i<=q && j<=r){
            if(sortArr[i] < sortArr[j]){
                tmp[k++] = sortArr[i++];
            }else{
                tmp[k++] = sortArr[j++];
            }
        }
        int start = i;
        int end = q;
        if(j<=r){
            start = j;
            end = r;
        }
        while(start<=end){
            tmp[k++] = sortArr[start++];
        }
        //将tmp中的数组拷贝回SortArr[p,r]
//        for(int b=0;b<tmp.length;b++){
//            sortArr[b] = tmp[b];
//        }
        // 将tmp中的数组拷贝回a[p...r]
        for (i = 0; i <= r-p; ++i) {
            sortArr[p+i] = tmp[i];
        }

    }
    /**
     * 快速排序写法
     * 1：写出递推公式
     * 2：找出终止条件
     * f(n) = f(n-1)+1
     * f(1) = 1;
     * 递推公式：quickSort_c(p,r) = quickSort_c(p,q-1)+quickSort_c(q+1,r)
     * 先分区，再快排
     * 终止条件：p>=r
     * @return
     */
    public int[] quickSort(){
        quickSort_c(sortArr,0,n-1);
        return sortArr;
    }

    private void quickSort_c(int[] sortArr, int p, int r) {
        if(p>=r) return;
        int q = partition(sortArr,p,r);
        quickSort_c(sortArr,p,q-1);
        quickSort_c(sortArr,q+1,r);
    }

    private int partition(int[] sortArr, int p, int r) {
        int pivot = sortArr[r];
        int i = p;
        for(int j=p;j<r;j++){
            if(sortArr[j]<pivot){
                if(i == j){
                    ++i;
                }else{
                    int tmp = sortArr[i];
                    sortArr[i] = sortArr[j];
                    sortArr[j] = tmp;
                    i++;
                }
            }
        }
        int tmp = sortArr[i];
        sortArr[i] = sortArr[r];
        sortArr[r] = tmp;
        return i;
    }

    /**
     * O(n)  时间复杂度内求无序数组中的第 K  大元素。比如， 4 ， 2 ， 5 ， 12 ， 3  这样一组数据，第 3  大元素就是 4 。
     *
     *
     */

    public int[] kSort(){
        kSort_c(sortArr,0,n-1,3);
        return sortArr;
    }

    public  int kSort_c(int[] arr, int l, int r, int k) {
        if (l >= r) {
            return 0;
        }
        int p = partition(arr, l, r);
        if ((p + 1) == k) {
            return arr[p];
        } else if ((p + 1) < k) {
            return kSort_c(sortArr, p + 1, r, k);
        } else {
            return kSort_c(sortArr, l, p - 1, k);
        }
    }





}
